﻿using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace BToolkit.ExeUtils
{
    /// <summary>
    /// 三张图实现无限拖动(每页支持上下滚动)
    /// </summary>
    public class ThreeScrollerPro : MonoBehaviour
    {
        public float pageDistance = 1920;
        [Space]
        public ScrollRect loader1;
        public ScrollRect loader2;
        public ScrollRect loader3;
        [Space]
        public BButton btnPrevious;
        public BButton btnNext;
        [Space]
        public bool canResize = true;

        public RectTransform rectTransform { get { return transform as RectTransform; } }
        public int currTextureIndex { get; private set; }
        List<RectTransform> loaders;
        Vector2 screenSize;
        Vector2 downPos, previousPos, targetPos;
        bool isDraging, isMoving;
        string[] paths = new string[0];
        bool nextSuccess, previousSuccess;
        Action<int> onChange;
        Canvas _parentCanvas;
        Canvas ParentCanvas
        {
            get
            {
                if (!_parentCanvas)
                {
                    _parentCanvas = GetComponentInParent<Canvas>();
                }
                return _parentCanvas;
            }
        }
        float t, b, c, d = 0.3f;
        Vector2 checkDirTouchDown;
        bool hasConfirmDir;

        void Awake()
        {
            loaders = new List<RectTransform>() {
                loader1.transform as RectTransform,
                loader2.transform as RectTransform,
                loader3.transform as RectTransform
            };

            if (btnPrevious)
            {
                btnPrevious.AddClick(() =>
                {
                    Previous();
                });
            }
            if (btnNext)
            {
                btnNext.AddClick(() =>
                {
                    Next();
                });
            }

            screenSize = BUtils.ScreenUISize(ParentCanvas);
        }

        public void SetContent(string[] paths, float pageDistance, Action<int> onChange = null)
        {
            //Debug.Log($"count:{paths.Length}");
            this.paths = paths;
            this.pageDistance = pageDistance;
            this.onChange = onChange;
            loaders[0].anchoredPosition = new Vector2(-pageDistance, 0);
            loaders[1].anchoredPosition = new Vector2(0, 0);
            loaders[2].anchoredPosition = new Vector2(pageDistance, 0);
            currTextureIndex = 0;
            if (paths.Length <= 1)
            {
                loaders[0].gameObject.SetActive(false);
                loaders[1].gameObject.SetActive(true);
                loaders[2].gameObject.SetActive(false);
                if (paths.Length == 1)
                {
                    loaders[1].GetComponentInChildren<TextureLoaderVideo>().LoadByFullPath(paths[currTextureIndex], canResize);
                    CheckShowBar(loaders[1]);
                }
            }
            else
            {
                loaders[0].gameObject.SetActive(false);
                loaders[1].gameObject.SetActive(true);
                loaders[2].gameObject.SetActive(true);
                loaders[1].GetComponentInChildren<TextureLoaderVideo>().LoadByFullPath(paths[currTextureIndex], canResize, true);
                loaders[2].GetComponentInChildren<TextureLoaderVideo>().LoadByFullPath(paths[currTextureIndex + 1], canResize, false);
                CheckShowBar(loaders[1]);
                CheckShowBar(loaders[2]);
            }
        }

        void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                OnTouchDown();
                checkDirTouchDown = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
            }

            if (Input.GetMouseButton(0))
            {
                if (!hasConfirmDir)
                {
                    Vector2 _pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                    if (Vector2.Distance(_pos, checkDirTouchDown) > 10)
                    {
                        if (Mathf.Abs(_pos.x - checkDirTouchDown.x) < Mathf.Abs(_pos.y - checkDirTouchDown.y))
                        {
                            //检测到是上下翻,立即结束掉左右翻的动作
                            isDraging = false;
                            InitTween(Vector2.zero);
                        }
                        hasConfirmDir = true;
                    }
                }
            }

            Vector2 pos = loaders[1].anchoredPosition;
            if (isDraging)
            {
                Vector2 _pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                Vector2 delta = _pos - previousPos;
                previousPos = _pos;
                pos += delta;
            }
            else
            {
                if (isMoving)
                {
                    if (t < d)
                    {
                        t += Time.deltaTime;
                        if (t > d) t = d;
                        pos.x = EaseExpoOut(t, b, c, d);
                    }
                    else
                    {
                        isMoving = false;
                        targetPos = Vector2.zero;
                        if (nextSuccess)
                        {
                            onChange?.Invoke(currTextureIndex);
                            RectTransform last = loaders[0];
                            loaders.RemoveAt(0);
                            loaders.Add(last);
                            loaders[0].GetComponentInChildren<TextureLoaderVideo>().PauseVideo();
                            if (loaders[1].GetComponentInChildren<TextureLoaderVideo>().isVideo) loaders[1].GetComponentInChildren<TextureLoaderVideo>().PlayVideo(false, null);
                            loaders[2].GetComponentInChildren<TextureLoaderVideo>().PauseVideo();
                            last.SetAsLastSibling();
                            pos = Vector2.zero;
                            if (currTextureIndex < paths.Length - 1)
                            {
                                if (!last.gameObject.activeSelf) last.gameObject.SetActive(true);
                                last.GetComponentInChildren<TextureLoaderVideo>().LoadByFullPath(paths[currTextureIndex + 1], canResize, false);
                                CheckShowBar(last);
                            }
                            else
                            {
                                if (last.gameObject.activeSelf) last.gameObject.SetActive(false);
                            }
                            nextSuccess = false;
                        }
                        else if (previousSuccess)
                        {
                            onChange?.Invoke(currTextureIndex);
                            List<RectTransform> bridge = new List<RectTransform>() { loaders[2], loaders[0], loaders[1] };
                            loaders = bridge;
                            RectTransform first = loaders[0];
                            loaders[0].GetComponentInChildren<TextureLoaderVideo>().PauseVideo();
                            if (loaders[1].GetComponentInChildren<TextureLoaderVideo>().isVideo) loaders[1].GetComponentInChildren<TextureLoaderVideo>().PlayVideo(false, null);
                            loaders[2].GetComponentInChildren<TextureLoaderVideo>().PauseVideo();
                            first.SetAsFirstSibling();
                            pos = Vector2.zero;
                            if (currTextureIndex > 0)
                            {
                                if (!first.gameObject.activeSelf) first.gameObject.SetActive(true);
                                first.GetComponentInChildren<TextureLoaderVideo>().LoadByFullPath(paths[currTextureIndex - 1], canResize, false);
                                CheckShowBar(first);
                            }
                            else
                            {
                                if (first.gameObject.activeSelf) first.gameObject.SetActive(false);
                            }
                            previousSuccess = false;
                        }
                    }
                }
            }
            float y = loaders[1].anchoredPosition.y;
            loaders[0].anchoredPosition = new Vector2(pos.x - pageDistance, y);
            loaders[1].anchoredPosition = new Vector2(pos.x, y);
            loaders[2].anchoredPosition = new Vector2(pos.x + pageDistance, y);

            if (Input.GetMouseButtonUp(0))
            {
                OnTouchUp();
                hasConfirmDir = false;
            }
        }

        private void CheckShowBar(RectTransform cell)
        {
            ScrollRect scrollRect = cell.GetComponent<ScrollRect>();
            scrollRect.verticalNormalizedPosition = 1;
            bool showBar = scrollRect.content.sizeDelta.y > screenSize.y + 50;
            Vector2 _pos = (scrollRect.verticalScrollbar.transform as RectTransform).anchoredPosition;
            _pos.x = showBar ? -38 : 9999;
            (scrollRect.verticalScrollbar.transform as RectTransform).anchoredPosition = _pos;
        }

        private void OnTouchDown()
        {
            if (!isMoving)
            {
                downPos = previousPos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                isDraging = true;
                isMoving = true;
            }
        }

        private void OnTouchUp()
        {
            if (isDraging)
            {
                isDraging = false;
                Vector2 pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, ParentCanvas);
                float dis = pageDistance * 0.1f;
                if (downPos.x - pos.x > dis && currTextureIndex < paths.Length - 1 && currTextureIndex < paths.Length - 1)
                {
                    Next();
                    return;
                }
                if (pos.x - downPos.x > dis && currTextureIndex > 0 && currTextureIndex > 0)
                {
                    Previous();
                    return;
                }
                InitTween(Vector2.zero);
            }
        }

        void Previous()
        {
            if (currTextureIndex > 0 && currTextureIndex > 0)
            {
                isMoving = true;
                currTextureIndex--;
                targetPos = new Vector2(pageDistance, 0);
                previousSuccess = true;
                InitTween(targetPos);
            }
        }

        void Next()
        {
            if (currTextureIndex < paths.Length - 1 && currTextureIndex < paths.Length - 1)
            {
                isMoving = true;
                currTextureIndex++;
                targetPos = new Vector2(-pageDistance, 0);
                nextSuccess = true;
                InitTween(targetPos);
            }
        }

        void InitTween(Vector2 toPos)
        {
            t = 0;
            b = loaders[1].anchoredPosition.x;
            c = toPos.x - b;
        }

        float EaseExpoOut(double t, double b, double c, double d)
        {
            if (t == d)
            {
                return (float)(b + c);
            }
            else
            {
                return (float)(c * (-Math.Pow(2, -10 * t / d) + 1) + b);
            }
        }
    }
}